#ifndef		__SCHEDULER_H_INCLUDED__
#define		__SCHEDULER_H_INCLUDED__

#include	<functional>
#include	<list>

#define		GScheduler	Scheduler::Instance()

/**
 * Timer and Daily schedule task manager.
 */
class Scheduler {

	/** Job definition. */
	typedef std::function<void(uint64_t)> Job;

	/** Task information */
	struct Task {
		uint64_t id;		//! Unique id to access this task.
		bool cancelled;		//! Has this job be cancelled?
		double trigger;		//! Next trigger time.
		double loop_delay;	//! Loop delay. >0 valid.
		Job job;			//! Task's job.
	};

public:
	Scheduler();

	/**
	 * Get runtime singleton instance.
	 */
	static Scheduler & Instance();

	/**
	 * Add timer task.
	 *
	 * \param delay Delay time in milliseconds to run this job.
	 * \param job Job to do.
	 * \param loop Optional. Pass true to enable looping.
	 * \return Task id for future access.
	 */
	uint64_t Add(double delay, const Job & job, bool loop = false);

	/**
	 * Add daily schedule task.
	 *
	 * \param hour Hour. [0, 23]
	 * \param minute Minute. [0, 59]
	 * \param second Second. [0, 59]
	 * \param job Job to do.
	 * \return Task id for future access.
	 */
	uint64_t Add(int hour, int minute, int second, const Job & job);

	/**
	 * Is an timer or daily task on schedule.
	 * 
	 * \param id Task id generated by Scheduler.Add
	 */
	bool IsValid(uint64_t id);

	/**
	 * Get remain time in milliseconds before running this job.
	 *
	 * \param id Task id generated by Scheduler.Add
	 */
	double GetRemainTime(uint64_t id);

	/**
	 * Cancel a job from schedule.
	 *
	 * \param id Task id generated by Scheduler.Add
	 */
	void Cancel(uint64_t id);

	/**
	 * Tick per frame.
	 */
	void Breath();

private:
	uint64_t __Add(double trigger, double loop, const Job & job);

private:
	uint64_t _alloc_id;
	double _next;
	bool _is_breathing;
	std::list<Task *> _tasks;
};

#endif//!	__SCHEDULER_H_INCLUDED__
